package com.centriole.common.utils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 *  功   能：针对bean的一些工具类方法
 *  创建人：陈默晗
 *  时   间：2018年4月27日下午14:40:45
 */
public class BeanUtils {

    /* 判断 一个字符串是不是 实数 的正则*/
    private static Pattern pattern = Pattern.compile("^[+-]?\\d+(\\.\\d+)?$");

    public static Map<String,String> toStringMap(Object bean){
        return toStringMap(bean,"remoteHost");
    }

    /**
     * 将bean的 属性 转换成key-value形式 ，【其中key为String类型,value为String类型】
     * 注意: 如果 是可以被转换成字符串类型的类型，比如整形int,也会放到map结果集中
     * @param bean                           要转换成map的bean
     * @param ignoredAtrributeNames    忽略的属性名
     * @return
     */
    public static Map<String,String> toStringMap(Object bean , String ... ignoredAtrributeNames){
        return toMap(bean, String.class, ignoredAtrributeNames);
    //    Map<String, String> rawMap = toMap(bean, String.class, ignoredAtrributeNames);
   //     return rawMap.entrySet().parallelStream()
  //                                      .collect(Collectors.toMap( e->e.getKey() , e->e.getValue()+"" ));
    }

    /**
     *将bean的 属性 转换成key-value形式 ，【其中key为String类型,value为Object类型】
     * @param bean                          要转换成map的bean
     * @param ignoredAtrributeNames   忽略的属性名
     * @return
     */
    public static Map<String,Object> toMap(Object bean,  String ... ignoredAtrributeNames){
        return toMap(bean,Object.class , ignoredAtrributeNames);
    }

    /**
     *将bean的 属性 转换成key-value形式
     * @param bean
     * @param ignoredAtrributeNames   忽略的属性名
     * @return
     */
    private static <T>Map<String,T> toMap(Object bean, Class<T> clazz , String ... ignoredAtrributeNames){
        if(bean == null ) return new HashMap<String, T>();
        /*---组装忽略参数字符串，形如这个样子: "class-fieldA-fieldB"
        // 那么如果该bean中存在"fieldA"的属性将不会放到map中，"class"、"filedB"也是如此
        StringBuilder sb = new StringBuilder("class");
        for(String field : ignoredAtrributeNames){
            sb.append("-"+field);
        }
        String ignoreString = sb.toString();

        //---组装结束*/
        List<String> filteredKeywords = Arrays.asList(ignoredAtrributeNames);
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            HashMap map = new HashMap();
            for(PropertyDescriptor descriptor : propertyDescriptors){
            //    if(ignoreString.contains( descriptor.getDisplayName() )) continue;
                if(   filteredKeywords.contains( descriptor.getDisplayName() )) continue;
                String displayName = descriptor.getDisplayName();
                Method readMethod = descriptor.getReadMethod();
                Object value = readMethod.invoke(bean, null);
                //值为null的属性不放入到map中，
                // 如果传入的泛型为Object，那么所有属性都会放入到map中
                //如果传入的泛型为String，那么只会将属性类型为字符串、数值的放入到map中
                if( value != null && ( clazz.equals(Object.class) || checkIsNumberOrString(value)) ){
                    if(clazz.equals(String.class)){
                        map.put(displayName,value.toString());
                    }else{
                        map.put(displayName,value);
                    }
                }
            }
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<String, T>();
        }
    }

    /**
     * 检查这个对象能否被转换成 数值类型或者 字符串类型
     * @param target
     * @return  满足任意一个条件返回true，否则返回false;
     */
    private static boolean checkIsNumberOrString(Object target){
        try {
            String s = (String)target;
            return true;
        }catch (Exception e){
            return pattern.matcher((target.toString()+"")).find();
        }
    }

}
